home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 19 / Mac Magazin and MacEasy Magazine CD - Issue 19.iso / Utilities / uae-0.4 / Source Code / filesys.c < prev    next >
Text File  |  1996-02-05  |  36KB  |  1,634 lines

  1.  /* 
  2.   * UAE - The Un*x Amiga Emulator
  3.   * 
  4.   * Unix file system handler for AmigaDOS
  5.   *
  6.   * (c) 1996 Ed Hanway
  7.   *
  8.   * Version 0.1: 28-Jan-1996
  9.   *
  10.   * Based on example code (c) 1988 The Software Distillery
  11.   * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
  12.   * (May - August 1989)
  13.   *
  14.   * Known limitations:
  15.   * Does not support ACTION_INHIBIT (big deal).
  16.   * Does not support any 2.0+ packet types (except ACTION_SAME_LOCK)
  17.   * Does not actually enforce exclusive locks.
  18.   * Does not support removable volumes.
  19.   * May not return the correct error code in some cases.
  20.   * Does not check for sane values passed by AmigaDOS.  May crash the emulation
  21.   * if passed garbage values.
  22.   *
  23.   * TODO someday:
  24.   * Support booting.
  25.   * Implement real locking using flock.  Needs test cases.
  26.   */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <strings.h>
  32. #include <assert.h>
  33.  
  34. #ifdef __unix
  35. #include <unistd.h>
  36. #include <fcntl.h>
  37. #include <sys/vfs.h>
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40. #ifndef __linux
  41. #include <sys/statfs.h>
  42. #endif
  43. #include <dirent.h>
  44. #include <utime.h>
  45. #include <errno.h>
  46. #endif
  47.  
  48. #include "config.h"
  49. #include "amiga.h"
  50. #include "options.h"
  51. #include "events.h"
  52. #include "memory.h"
  53. #include "custom.h"
  54. #include "newcpu.h"
  55. #include "xwin.h"
  56. #include "autoconf.h"
  57. #include "filesys.h"
  58.  
  59. #define MAKE_CASE_INSENSITIVE
  60.  
  61. typedef struct {
  62.     char *devname; /* device name, e.g. UAE0: */
  63.     char *volname; /* volume name, e.g. CDROM, WORK, etc. */
  64.     char *rootdir; /* root unix directory */
  65.     bool readonly; /* disallow write access? */
  66. } UnitInfo;
  67.  
  68. #define MAX_UNITS 20
  69. static int num_units = 0;
  70. static UnitInfo ui[MAX_UNITS];
  71.  
  72. static ULONG devnameaddr[100];
  73.  
  74. static ULONG doslibname, fsdevname, filesysseglist;
  75.  
  76. /* strdup missing? */
  77. static char*
  78. my_strdup(const char*s)
  79. {
  80.     char*x = (char*)malloc(strlen(s) + 1);
  81.     strcpy(x, s);
  82.     return x;
  83. }
  84.  
  85.  
  86. void
  87. add_filesys_unit(char *volname, char *rootdir, bool readonly)
  88. {
  89.     UnitInfo* u;
  90.     static char buf[80];
  91.  
  92.     if (num_units >= MAX_UNITS) {
  93.     fprintf(stderr, "Maximum number of unix file systems mounted.\n");
  94.     return;
  95.     }
  96.  
  97.     u = &ui[num_units];
  98.     sprintf(buf, "UAE%d", num_units);
  99.     u->devname = my_strdup(buf);
  100.     u->volname = my_strdup(volname);
  101.     u->rootdir = my_strdup(rootdir);
  102.     u->readonly = readonly;
  103.  
  104.     num_units++;
  105. }
  106.  
  107. #ifdef TRACING_ENABLED
  108. #define TRACE(x)    printf x;
  109. #define DUMPLOCK(x)    dumplock(x)
  110. #else
  111. #define TRACE(x)
  112. #define DUMPLOCK(x)
  113. #endif
  114.  
  115. /* minimal AmigaDOS definitions */
  116.  
  117. /* field offsets in DosPacket */
  118. #define dp_Type (8)
  119. #define dp_Res1    (12)
  120. #define dp_Res2 (16)
  121. #define dp_Arg1 (20)
  122. #define dp_Arg2 (24)
  123. #define dp_Arg3 (28)
  124. #define dp_Arg4 (32)
  125.  
  126. /* result codes */
  127. #define DOS_TRUE (-1L)
  128. #define DOS_FALSE (0L)
  129.  
  130. /* packet types */
  131. #define ACTION_CURRENT_VOLUME    7
  132. #define ACTION_LOCATE_OBJECT    8
  133. #define ACTION_RENAME_DISK    9
  134. #define ACTION_FREE_LOCK    15
  135. #define ACTION_DELETE_OBJECT    16
  136. #define ACTION_RENAME_OBJECT    17
  137. #define ACTION_COPY_DIR        19
  138. #define ACTION_SET_PROTECT    21
  139. #define ACTION_CREATE_DIR    22
  140. #define ACTION_EXAMINE_OBJECT    23
  141. #define ACTION_EXAMINE_NEXT    24
  142. #define ACTION_DISK_INFO    25
  143. #define ACTION_INFO        26
  144. #define ACTION_FLUSH        27
  145. #define ACTION_SET_COMMENT    28
  146. #define ACTION_PARENT        29
  147. #define ACTION_SET_DATE        34
  148. #define ACTION_SAME_LOCK    40
  149. #define ACTION_FIND_WRITE    1004
  150. #define ACTION_FIND_INPUT    1005
  151. #define ACTION_FIND_OUTPUT    1006
  152. #define ACTION_END        1007
  153. #define ACTION_SEEK        1008
  154. #define ACTION_IS_FILESYSTEM    1027
  155. #define ACTION_READ        'R'
  156. #define ACTION_WRITE        'W'
  157.  
  158. #define DISK_TYPE        (0x444f5301) /* DOS\1 */
  159.  
  160. /* errors */
  161. #define ERROR_NO_FREE_STORE     103
  162. #define ERROR_OBJECT_IN_USE    202
  163. #define ERROR_OBJECT_EXISTS     203
  164. #define ERROR_DIR_NOT_FOUND     204
  165. #define ERROR_OBJECT_NOT_FOUND  205
  166. #define ERROR_ACTION_NOT_KNOWN  209
  167. #define ERROR_OBJECT_WRONG_TYPE 212
  168. #define ERROR_DISK_WRITE_PROTECTED 214
  169. #define ERROR_DIRECTORY_NOT_EMPTY 216
  170. #define ERROR_DEVICE_NOT_MOUNTED 218
  171. #define ERROR_SEEK_ERROR    219
  172. #define ERROR_DISK_FULL        221
  173. #define ERROR_WRITE_PROTECTED 223
  174. #define ERROR_NO_MORE_ENTRIES  232
  175. #define ERROR_NOT_IMPLEMENTED    236
  176.  
  177. static long dos_errno(void)
  178. {
  179.     int e = errno;
  180.  
  181.     switch(e) {
  182.      case ENOMEM:    return ERROR_NO_FREE_STORE;
  183.      case EEXIST:    return ERROR_OBJECT_EXISTS;
  184.      case EISDIR:    return ERROR_OBJECT_WRONG_TYPE;
  185.      case ETXTBSY:    return ERROR_OBJECT_IN_USE;
  186.      case EACCES:    return ERROR_WRITE_PROTECTED;
  187.      case ENOENT:    return ERROR_OBJECT_NOT_FOUND;
  188.      case ENOTDIR:    return ERROR_OBJECT_WRONG_TYPE;
  189.      case EROFS:           return ERROR_DISK_WRITE_PROTECTED;
  190.      case ENOSPC:    return ERROR_DISK_FULL;
  191.      case EBUSY:           return ERROR_OBJECT_IN_USE;
  192.      case ENOTEMPTY:    return ERROR_DIRECTORY_NOT_EMPTY;
  193.     
  194.      default:
  195.     TRACE(("Unimplemented error %s\n", strerror(e)));
  196.     return ERROR_NOT_IMPLEMENTED;
  197.     }
  198. }
  199.  
  200. /* handler state info */
  201.  
  202. typedef struct _unit {
  203.     struct _unit *next;
  204.  
  205.     /* Amiga stuff */
  206.     CPTR    dosbase;
  207.     CPTR    volume;
  208.     CPTR    port;    /* Our port */
  209.  
  210.     /* Native stuff */
  211.     long    unit;    /* unit number */
  212.     UnitInfo    ui;    /* unit startup info */
  213. } Unit;
  214.  
  215. typedef struct {
  216.     CPTR addr; /* addr of real packet */
  217.     long type;
  218.     long res1;
  219.     long res2;
  220.     long arg1;
  221.     long arg2;
  222.     long arg3;
  223.     long arg4;
  224. } DosPacket;
  225.  
  226. static char *
  227. bstr(CPTR addr)
  228. {
  229.     static char buf[256];
  230.     int n = get_byte(addr++);
  231.     int i;
  232.     for(i = 0; i < n; i++)
  233.     buf[i] = get_byte(addr++);
  234.     buf[i] = 0;
  235.     return buf;
  236. }
  237.  
  238. static Unit *units = NULL;
  239. static int unit_num = 0;
  240.  
  241. static Unit*
  242. find_unit(CPTR port)
  243. {
  244.     Unit* u;
  245.     for(u = units; u; u = u->next)
  246.     if(u->port == port)
  247.         break;
  248.  
  249.     return u;
  250. }
  251.  
  252. static CPTR DosAllocMem(ULONG len)
  253. {
  254.     ULONG i;
  255.     CPTR addr;
  256.  
  257.     regs.d[0] = len + 4;
  258.     regs.d[1] = 1; /* MEMF_PUBLIC */
  259.     addr = CallLib(regs.a[6], -198); /* AllocMem */
  260.  
  261.     if(addr) {
  262.     put_long(addr, len);
  263.     addr += 4;
  264.  
  265.     /* faster to clear memory here rather than use MEMF_CLEAR */
  266.     for(i = 0; i < len; i += 4) 
  267.         put_long(addr + i, 0);
  268.     }
  269.  
  270.     return addr;
  271. }
  272.  
  273. static void DosFreeMem(CPTR addr)
  274. {
  275.     addr -= 4;
  276.     regs.d[0] = get_long(addr) + 4;
  277.     regs.a[1] = addr;
  278.     CallLib(regs.a[6], -210); /* FreeMem */
  279. }
  280.  
  281. static void
  282. startup(DosPacket* packet)
  283. {
  284.     int i, namelen;
  285.     char* devname = bstr(packet->arg1 << 2);
  286.     char* s;
  287.     Unit* unit;
  288.  
  289.     /* find UnitInfo with correct device name */
  290.     s = strchr(devname, ':');
  291.     if(s) *s = '\0';
  292. #if 0 /* Kick 1.3 send us a bogus string. */
  293.     for(i = 0; i < num_units; i++) {
  294.     if(0 == strcmp(ui[i].devname, devname))
  295.         break;
  296.     }
  297. #endif
  298.     
  299.     i = 0;
  300.     
  301.     if(i == num_units || 0 != access(ui[i].rootdir, R_OK)) {
  302.     fprintf(stderr, "Failed attempt to mount device %s\n", devname);
  303.     packet->res1 = DOS_FALSE;
  304.     packet->res2 = ERROR_DEVICE_NOT_MOUNTED;
  305.     return;
  306.     }
  307.  
  308.     unit = (Unit *) malloc(sizeof(Unit));
  309.     unit->next = units;
  310.     units = unit;
  311.  
  312.     unit->volume = 0;
  313.     unit->port = regs.a[5];
  314.     unit->unit = unit_num++;
  315.  
  316.     unit->ui.devname = ui[i].devname;
  317.     unit->ui.volname = my_strdup(ui[i].volname); /* might free later for rename */
  318.     unit->ui.rootdir = ui[i].rootdir;
  319.     unit->ui.readonly = ui[i].readonly;
  320.  
  321.     TRACE(("**** STARTUP volume %s\n", unit->ui.volname));
  322.  
  323.     /* fill in our process in the device node */
  324.     put_long((packet->arg3 << 2) + 8, unit->port);
  325.  
  326.     /* open dos.library */
  327.     regs.d[0] = 0;
  328.     regs.a[1] = doslibname;
  329.     unit->dosbase = CallLib(regs.a[6], -552); /* OpenLibrary */
  330.  
  331.     {
  332.         CPTR rootnode = get_long(unit->dosbase + 34);
  333.         CPTR dos_info = get_long(rootnode + 24) << 2;
  334.         /* make new volume */
  335.         unit->volume = DosAllocMem(80 + 1 + 44);
  336.         put_long(unit->volume + 4, 2); /* Type = dt_volume */
  337.         put_long(unit->volume + 12, 0); /* Lock */
  338.         put_long(unit->volume + 16, 3800); /* Creation Date */
  339.         put_long(unit->volume + 20, 0);
  340.         put_long(unit->volume + 24, 0);
  341.         put_long(unit->volume + 28, 0); /* lock list */
  342.         put_long(unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
  343.         namelen = strlen(unit->ui.volname);
  344.         put_byte(unit->volume + 44, namelen);
  345.         for(i = 0; i < namelen; i++)
  346.         put_byte(unit->volume + 45 + i, unit->ui.volname[i]);
  347.         
  348.         /* link into DOS list */
  349.         put_long(unit->volume, get_long(dos_info + 4));
  350.         put_long(dos_info + 4, unit->volume >> 2);
  351.     }
  352.  
  353.     put_long(unit->volume + 8, unit->port);
  354.     put_long(unit->volume + 32, DISK_TYPE);
  355.  
  356.     packet->res1 = DOS_TRUE;
  357. }
  358.  
  359. static void
  360. do_info(Unit* unit, DosPacket* packet, CPTR info)
  361. {
  362.     struct statfs statbuf;
  363. #ifdef __linux
  364.     if(-1 == statfs(unit->ui.rootdir, &statbuf))
  365. #else
  366.     if(-1 == statfs(unit->ui.rootdir, &statbuf, sizeof(struct statfs), 0))
  367. #endif
  368.     {
  369.     packet->res1 = DOS_FALSE;
  370.     packet->res2 = dos_errno();
  371.     }
  372.  
  373.     put_long(info, 0); /* errors */
  374.     put_long(info + 4, unit->unit); /* unit number */
  375.     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
  376.     put_long(info + 12, statbuf.f_blocks); /* numblocks */
  377. #ifdef __linux
  378.     put_long(info + 16, statbuf.f_blocks - statbuf.f_bavail); /* inuse */
  379. #else
  380.     put_long(info + 16, statbuf.f_blocks - statbuf.f_bfree); /* inuse */
  381. #endif
  382.     put_long(info + 20, statbuf.f_bsize); /* bytesperblock */
  383.     put_long(info + 24, DISK_TYPE); /* disk type */
  384.     put_long(info + 28, unit->volume >> 2); /* volume node */
  385.     put_long(info + 32, 0); /* inuse */
  386.     packet->res1 = DOS_TRUE;
  387. }
  388.  
  389. static void
  390. action_disk_info(Unit* unit, DosPacket* packet)
  391. {
  392.     TRACE(("ACTION_DISK_INFO\n"));
  393.     do_info(unit, packet, packet->arg1 << 2);
  394. }
  395.  
  396. static void
  397. action_info(Unit* unit, DosPacket* packet)
  398. {
  399.     TRACE(("ACTION_INFO\n"));
  400.     do_info(unit, packet, packet->arg2 << 2);
  401. }
  402.  
  403. typedef struct {
  404.     char *path;
  405.     int fd;
  406. } Key;
  407.  
  408. static void
  409. free_key(Key*k)
  410. {
  411.     free(k->path);
  412.     free(k);
  413. }
  414.  
  415. static void
  416. dumplock(CPTR lock)
  417. {
  418.     if(!lock) {
  419.     fprintf(stderr, "LOCK: 0x0\n");
  420.     return;
  421.     }
  422.     fprintf(stderr,
  423.         "LOCK: 0x%lx { next=0x%lx, key=%s, mode=%ld, handler=0x%lx, volume=0x%lx }\n",
  424.         lock,
  425.         get_long(lock)<<2, ((Key*)get_long(lock+4))->path, get_long(lock+8),
  426.         get_long(lock+12), get_long(lock+16));
  427. }
  428.  
  429. static char*
  430. get_path(Unit* unit, const char *base, const char *rel)
  431. {
  432.     static char buf[1024];
  433.     char *s = buf;
  434.     char *p;
  435.     char *r;
  436.  
  437.     int i;
  438.  
  439.     TRACE(("get_path(%s,%s)\n", base, rel));
  440.  
  441.     /* root-relative path? */
  442.     for(i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++);
  443.     if(':' == rel[i]) {
  444.     base = unit->ui.rootdir; rel += i+1;
  445.     }
  446.  
  447.     while(*base) {
  448.     *s++ = *base++;
  449.     }
  450.     p = s; /* start of relative path */
  451.     r = buf + strlen(unit->ui.rootdir); /* end of fixed path */
  452.     
  453.     while(*rel) {
  454.     /* start with a slash? go up a level. */
  455.     if('/' == *rel) {
  456.         while(s > r && '/' != *s)
  457.         s--;
  458.         rel++;
  459.     } else {
  460.         *s++ = '/';
  461.         while(*rel && '/' != *rel) {
  462.         *s++ = *rel++;
  463.         }
  464.         if('/' == *rel)
  465.         rel++;
  466.     }
  467.     }
  468.     *s = 0;
  469.  
  470. #ifdef MAKE_CASE_INSENSITIVE
  471.     TRACE(("path=\"%s\"\n", buf));
  472.     /* go through each section of the path and if it does not exist,
  473.      * scan its directory for any case insensitive matches
  474.      */
  475.     while(*p) {
  476.     char *p2 = strchr(p+1, '/');
  477.     char oldp2;
  478.     if(!p2) {
  479.         p2 = p+1;
  480.         while(*p2) p2++;
  481.     }
  482.     oldp2 = *p2;
  483.     *p2 = '\0';
  484.     if(0 != access(buf, F_OK|R_OK)) {
  485.         DIR* dir;
  486.         struct dirent* de;
  487.  
  488.         /* does not exist -- check dir for case insensitive match */
  489.         *p++ = '\0'; /* was '/' */
  490.         dir = opendir(buf);
  491.         if (dir) {
  492.         while((de = readdir(dir))) {
  493.             if(0 == strcasecmp(de->d_name, p))
  494.             break;
  495.         }
  496.         if(de) {
  497.             strcpy(p, de->d_name);
  498.         }
  499.         closedir(dir);
  500.         }
  501.         *--p = '/';
  502.     }
  503.     *p2 = oldp2;
  504.     p = p2;
  505.     }
  506. #endif
  507.     TRACE(("path=\"%s\"\n", buf));
  508.  
  509.     return my_strdup(buf);
  510. }
  511.  
  512. static Key*
  513. make_key(Unit* unit, CPTR lock, const char *name)
  514. {
  515.     Key *k = (Key*)malloc(sizeof(Key));
  516.  
  517.     k->fd = 0;
  518.  
  519.     if(!lock) {
  520.     k->path = get_path(unit, unit->ui.rootdir, name);
  521.     } else {
  522.     Key*oldk = (Key*)get_long(lock + 4);
  523.     TRACE(("key: 0x%08lx", (ULONG)oldk));
  524.     TRACE((" \"%s\"\n", oldk->path));
  525.     k->path = get_path(unit, oldk->path, name);
  526.     }
  527.  
  528.     TRACE(("key=\"%s\"\n", k->path));
  529.     return k;
  530. }
  531.  
  532. static Key*
  533. dup_key(Key*k)
  534. {
  535.     Key *newk = (Key*)malloc(sizeof(Key));
  536.     newk->path = my_strdup(k->path);
  537.     newk->fd = 0;
  538.     return newk;
  539. }
  540.  
  541. static CPTR
  542. make_lock(Unit* unit, Key *key, long mode)
  543. {
  544.     /* allocate lock */
  545.     CPTR lock = DosAllocMem(20);
  546.  
  547.     put_long(lock + 4, (ULONG) key);
  548.     put_long(lock + 8, mode);
  549.     put_long(lock + 12, unit->port);
  550.     put_long(lock + 16, unit->volume >> 2);
  551.  
  552.     /* prepend to lock chain */
  553.     put_long(lock, get_long(unit->volume + 28));
  554.     put_long(unit->volume + 28, lock >> 2);
  555.  
  556.     DUMPLOCK(lock);
  557.     return lock;
  558. }
  559.  
  560. static void
  561. free_lock(Unit* unit, CPTR lock)
  562. {
  563.     if(!lock)
  564.     return;
  565.  
  566.     if(lock == get_long(unit->volume + 28) << 2) {
  567.     put_long(unit->volume + 28, get_long(lock));
  568.     } else {
  569.     CPTR current = get_long(unit->volume + 28);
  570.     CPTR next = 0;
  571.     while(current) {
  572.         next = get_long(current << 2);
  573.         if(lock == next << 2)
  574.         break;
  575.         current = next;
  576.     }
  577.     put_long(current << 2, get_long(lock));
  578.     }
  579.     free_key((Key*)get_long(lock + 4));
  580.     DosFreeMem(lock);
  581. }
  582.  
  583. static void
  584. action_lock(Unit* unit, DosPacket* packet)
  585. {
  586.     CPTR lock = packet->arg1 << 2;
  587.     CPTR name = packet->arg2 << 2;
  588.     long mode = packet->arg3;
  589.     int access_mode = (mode == -2) ? R_OK : R_OK|W_OK;
  590.     Key *k;
  591.  
  592.     TRACE(("ACTION_LOCK(0x%lx, \"%s\", %d)\n",lock, bstr(name), mode));
  593.     DUMPLOCK(lock);
  594.  
  595.     k = make_key(unit, lock, bstr(name));
  596.  
  597.     if(k && 0 == access(k->path, access_mode)) {
  598.     packet->res1 = make_lock(unit, k, mode) >> 2;
  599.     } else {
  600.     if(k)
  601.         free_key(k);
  602.     packet->res1 = 0;
  603.     packet->res2 = ERROR_OBJECT_NOT_FOUND;
  604.     }
  605. }
  606.  
  607. static void
  608. action_free_lock(Unit* unit, DosPacket* packet)
  609. {
  610.     CPTR lock = packet->arg1 << 2;
  611.     TRACE(("ACTION_FREE_LOCK(0x%lx)\n", lock));
  612.     DUMPLOCK(lock);
  613.     
  614.     free_lock(unit, lock);
  615.     
  616.     packet->res1 = DOS_TRUE;
  617. }
  618.  
  619. static void
  620. action_dup_lock(Unit* unit, DosPacket* packet)
  621. {
  622.     CPTR lock = packet->arg1 << 2;
  623.  
  624.     TRACE(("ACTION_DUP_LOCK(0x%lx)\n", lock));
  625.     DUMPLOCK(lock);
  626.  
  627.     if(!lock) {
  628.     packet->res1 = 0;
  629.     return;
  630.     }
  631.  
  632.     {
  633.     CPTR oldkey = get_long(lock + 4);
  634.     CPTR oldmode = get_long(lock + 8);
  635.     packet->res1 = make_lock(unit, dup_key((Key*)oldkey), oldmode) >> 2;
  636.     }
  637. }
  638.  
  639. /* convert time_t to/from AmigaDOS time */
  640. const int secs_per_day = 24 * 60 * 60;
  641. const int diff = (8 * 365 + 2) * (24 * 60 * 60);
  642.  
  643. static void
  644. get_time(time_t t, long* days, long* mins, long* ticks)
  645. {
  646.     /* time_t is secs since 1-1-1970 */
  647.     /* days since 1-1-1978 */
  648.     /* mins since midnight */
  649.     /* ticks past minute @ 50Hz */
  650.  
  651.     t -= diff;
  652.     *days = t / secs_per_day;
  653.     t -= *days * secs_per_day;
  654.     *mins = t / 60;
  655.     t -= *mins * 60;
  656.     *ticks = t * 50;
  657. }
  658.  
  659. static time_t
  660. put_time(long days, long mins, long ticks)
  661. {
  662.     time_t t;
  663.     t = ticks / 50;
  664.     t += mins * 60;
  665.     t += days * secs_per_day;
  666.     t += diff;
  667.     
  668.     return t;
  669. }
  670.  
  671.  
  672. typedef struct {
  673.     char *path;
  674.     DIR* dir;
  675. } ExamineKey;
  676.  
  677. /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
  678.  * some of these around
  679.  */
  680.  
  681. #define EXKEYS 100
  682. static ExamineKey examine_keys[EXKEYS];
  683. static int next_exkey = 0;
  684.  
  685. static void
  686. free_exkey(ExamineKey* ek)
  687. {
  688.     free(ek->path);
  689.     ek->path = 0;
  690.     if(ek->dir)
  691.     closedir(ek->dir);
  692. }
  693.  
  694. static ExamineKey*
  695. new_exkey(char *path)
  696. {
  697.     ExamineKey* ek= &examine_keys[next_exkey++];
  698.     if(next_exkey==EXKEYS)
  699.     next_exkey = 0;
  700.     if(ek->path) {
  701.     free_exkey(ek);
  702.     }
  703.     ek->path = my_strdup(path);
  704.     ek->dir = 0;
  705.     return ek;
  706. }
  707.  
  708. static void
  709. get_fileinfo(DosPacket* packet, CPTR info, char *buf)
  710. {
  711.     struct stat statbuf;
  712.     long days, mins, ticks;
  713.  
  714.     if(-1 == stat(buf, &statbuf)) {
  715.     packet->res1 = DOS_FALSE;
  716.     packet->res2 = dos_errno();
  717.     } else {
  718.     put_long(info + 4, S_ISDIR(statbuf.st_mode) ? 2 : -3);
  719.     {
  720.         /* file name */
  721.         int i = 8;
  722.         int n;
  723.         char *x = strrchr(buf,'/');
  724.         if(x)
  725.         x++;
  726.         else
  727.         x = buf;
  728.         TRACE(("name=\"%s\"\n", x));
  729.         n = strlen(x);
  730.         if(n > 106) n = 106;
  731.         put_byte(info + i++, n);
  732.         while(n--)
  733.         put_byte(info + i++, *x++);
  734.         while(i < 108)
  735.         put_byte(info + i++, 0);
  736.     }
  737.     put_long(info + 116,
  738.          (S_IRUSR & statbuf.st_mode ? 0 : (1<<3)) |
  739.          (S_IWUSR & statbuf.st_mode ? 0 : (1<<2)) |
  740.          (S_IXUSR & statbuf.st_mode ? 0 : (1<<1)) |
  741.          (S_IWUSR & statbuf.st_mode ? 0 : (1<<0)));
  742.     put_long(info + 120, S_ISDIR(statbuf.st_mode) ? 2 : -3);
  743.     put_long(info + 124, statbuf.st_size);
  744.     put_long(info + 128, statbuf.st_blocks);
  745.     get_time(statbuf.st_mtime, &days, &mins, &ticks);
  746.     put_long(info + 132, days);
  747.     put_long(info + 136, mins);
  748.     put_long(info + 140, ticks);
  749.     put_long(info + 144, 0); /* no comment */
  750.     packet->res1 = DOS_TRUE;
  751.     }
  752. }
  753.  
  754. static void
  755. do_examine(DosPacket* packet, ExamineKey* ek, CPTR info)
  756. {
  757.     static char buf[1024];
  758.     struct dirent* de;
  759.  
  760.     if(!ek->dir) {
  761.     ek->dir = opendir(ek->path);
  762.     }
  763.     if(!ek->dir) {
  764.     free_exkey(ek);
  765.     packet->res1 = DOS_FALSE;
  766.     packet->res2 = ERROR_NO_MORE_ENTRIES;
  767.     return;
  768.     }
  769.     
  770.     de = readdir(ek->dir);
  771.     
  772.     while(de &&
  773.       (0 == strcmp(".", de->d_name) ||
  774.        0 == strcmp("..", de->d_name))) 
  775.     {
  776.     de = readdir(ek->dir);
  777.     }
  778.  
  779.     if(!de) {
  780.     TRACE(("no more entries\n"));
  781.     free_exkey(ek);
  782.     packet->res1 = DOS_FALSE;
  783.     packet->res2 = ERROR_NO_MORE_ENTRIES;
  784.     return;
  785.     }
  786.  
  787.     TRACE(("entry=\"%s\"\n", de->d_name));
  788.  
  789.     sprintf(buf, "%s/%s", ek->path, de->d_name);
  790.  
  791.     get_fileinfo(packet, info, buf);
  792. }
  793.  
  794. static void
  795. action_examine_object(Unit* unit, DosPacket* packet)
  796. {
  797.     CPTR lock = packet->arg1 << 2;
  798.     CPTR info = packet->arg2 << 2;
  799.     char *path;
  800.     ExamineKey* ek;
  801.     
  802.     TRACE(("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info));
  803.     DUMPLOCK(lock);
  804.  
  805.     if(!lock) {
  806.     path = unit->ui.rootdir;
  807.     } else {
  808.     Key*k = (Key *)get_long(lock + 4);
  809.     path = k->path;
  810.     }
  811.     
  812.     get_fileinfo(packet, info, path);
  813.     ek = new_exkey(path);
  814.     put_long(info, (ULONG)ek);
  815. }
  816.  
  817. static void
  818. action_examine_next(Unit* unit, DosPacket* packet)
  819. {
  820.     CPTR lock = packet->arg1 << 2;
  821.     CPTR info = packet->arg2 << 2;
  822.  
  823.     TRACE(("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info));
  824.     DUMPLOCK(lock);
  825.  
  826.     do_examine(packet, (ExamineKey*)get_long(info), info);
  827. }
  828.  
  829. static void
  830. do_find(Unit* unit, DosPacket* packet, mode_t mode)
  831. {
  832.     CPTR fh = packet->arg1 << 2;
  833.     CPTR lock = packet->arg2 << 2;
  834.     CPTR name = packet->arg3 << 2;
  835.     Key *k;
  836.     struct stat st;
  837.     
  838.     TRACE(("ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n",fh,lock,bstr(name),mode));
  839.     DUMPLOCK(lock);
  840.  
  841.     k = make_key(unit, lock, bstr(name));
  842.     if(!k) {
  843.     packet->res1 = DOS_FALSE;
  844.     packet->res2 = ERROR_NO_FREE_STORE;
  845.     return;
  846.     }
  847.  
  848.     /* Fixme: may not quite be right */
  849.     if (0 == stat (k->path, &st)) {
  850.     if (S_ISDIR (st.st_mode)) {
  851.         packet->res1 = DOS_FALSE;
  852.         packet->res2 = ERROR_OBJECT_WRONG_TYPE;
  853.         return;
  854.     }
  855.     }
  856.  
  857.     k->fd = open(k->path, mode, 0777);
  858.  
  859.     if(k->fd < 0) {
  860.     packet->res1 = DOS_FALSE;
  861.     packet->res2 = dos_errno();
  862.     free_key(k);
  863.     return;
  864.     }
  865.     success:
  866.     put_long(fh+36, (ULONG)k);
  867.  
  868.     packet->res1 = DOS_TRUE;
  869. }
  870.  
  871. static void
  872. action_find_input(Unit* unit, DosPacket* packet)
  873. {
  874.     do_find(unit, packet, O_RDONLY);
  875. }
  876.  
  877. static void
  878. action_find_output(Unit* unit, DosPacket* packet)
  879. {
  880.     if(unit->ui.readonly) {
  881.     packet->res1 = DOS_FALSE;
  882.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  883.     return;
  884.     }
  885.     do_find(unit, packet, O_WRONLY|O_CREAT|O_TRUNC);
  886. }
  887.  
  888. static void
  889. action_find_write(Unit* unit, DosPacket* packet)
  890. {
  891.     if(unit->ui.readonly) {
  892.     packet->res1 = DOS_FALSE;
  893.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  894.     return;
  895.     }
  896.     do_find(unit, packet, O_RDWR);
  897. }
  898.  
  899. static void
  900. action_end(Unit* unit, DosPacket* packet)
  901. {
  902.     Key*k;
  903.     TRACE(("ACTION_END(0x%lx)\n", packet->arg1));
  904.  
  905.     k = (Key*)(packet->arg1);
  906.     close(k->fd);
  907.     free_key(k);
  908.     packet->res1 = DOS_TRUE;
  909. }
  910.  
  911. static void
  912. action_read(Unit* unit, DosPacket* packet)
  913. {
  914.     Key*k = (Key*)(packet->arg1);
  915.     CPTR addr = packet->arg2;
  916.     long size = packet->arg3;
  917.     int actual;
  918.     char *buf;
  919.     
  920.     TRACE(("ACTION_READ(%s,0x%lx,%ld)\n",k->path,addr,size));
  921.     
  922.     /* ugh this is inefficient but easy */
  923.     buf = (char *)malloc(size);
  924.     if(!buf) {
  925.     packet->res1 = -1;
  926.     packet->res2 = ERROR_NO_FREE_STORE;
  927.     return;
  928.     }
  929.     
  930.     actual = read(k->fd, buf, size);
  931.  
  932.     packet->res1 = actual;
  933.  
  934.     if(actual > 0) {
  935.     int i;
  936.     unsigned char *bp = (unsigned char *)buf;
  937.     UWORD *realpt;
  938.     if (addr & 1) { /* Eeek! */
  939.         actual--;
  940.         put_byte(addr, *bp++);
  941.         addr++;
  942.     }
  943.     if (valid_address (addr, actual)) {
  944.         realpt = get_real_address (addr);
  945.         for (i = 0; i < (actual & ~1); i+=2) {
  946.         UWORD data = ((UWORD)(*bp++) << 8);
  947.         data |= *bp++;
  948.         *realpt++ = data;
  949.         }
  950.         if (actual & 1)
  951.         put_byte (addr + actual - 1, *bp);
  952.     } else {
  953.        /* fprintf (stderr, "unixfs warning: Bad pointer passed for read\n");*/
  954.         for(i = 0; i < actual; i++) 
  955.         put_byte(addr + i, buf[i]);
  956.     }
  957.     } else {
  958.     packet->res2 = dos_errno();
  959.     }
  960.     free(buf);
  961. }
  962.  
  963. static void
  964. action_write(Unit* unit, DosPacket* packet)
  965. {
  966.     Key*k = (Key*)(packet->arg1);
  967.     CPTR addr = packet->arg2;
  968.     long size = packet->arg3;
  969.     char *buf;
  970.     int i;
  971.  
  972.     TRACE(("ACTION_WRITE(%s,0x%lx,%ld)\n",k->path,addr,size));
  973.  
  974.     if(unit->ui.readonly) {
  975.     packet->res1 = DOS_FALSE;
  976.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  977.     return;
  978.     }
  979.  
  980.     /* ugh this is inefficient but easy */
  981.     buf = (char *)malloc(size);
  982.     if(!buf) {
  983.     packet->res1 = -1;
  984.     packet->res2 = ERROR_NO_FREE_STORE;
  985.     return;
  986.     }
  987.     
  988.     for(i = 0; i < size; i++)
  989.     buf[i] = get_byte(addr + i);
  990.  
  991.     packet->res1 = write(k->fd, buf, size);
  992.     if(packet->res1 != size)
  993.     packet->res2 = dos_errno();
  994.  
  995.     free(buf);
  996. }
  997.  
  998. static void
  999. action_seek(Unit* unit, DosPacket* packet)
  1000. {
  1001.     Key* k = (Key*) (packet->arg1);
  1002.     long pos = packet->arg2;
  1003.     long mode = packet->arg3;
  1004.     off_t res;
  1005.     long old;
  1006.     int whence = SEEK_CUR;
  1007.     if(mode > 0) whence = SEEK_END;
  1008.     if(mode < 0) whence = SEEK_SET;
  1009.  
  1010.     TRACE(("ACTION_SEEK(%s,%d,%d)\n",k->path,pos,mode));
  1011.  
  1012.     old = lseek(k->fd, 0, SEEK_CUR);
  1013.     res = lseek(k->fd, pos, whence);
  1014.  
  1015.     if(-1 == res)
  1016.     packet->res1 = res;
  1017.     else
  1018.     packet->res1 = old;
  1019. }
  1020.  
  1021. static void
  1022. action_set_protect(Unit* unit, DosPacket* packet)
  1023. {
  1024.     CPTR lock = packet->arg2 << 2;
  1025.     CPTR name = packet->arg3 << 2;
  1026.     ULONG mask = packet->arg4;
  1027.     struct stat statbuf;
  1028.     mode_t mode;
  1029.     Key *k;
  1030.  
  1031.     TRACE(("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n",lock,bstr(name),mask));
  1032.  
  1033.     if(unit->ui.readonly) {
  1034.     packet->res1 = DOS_FALSE;
  1035.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1036.     return;
  1037.     }
  1038.  
  1039.     k = make_key(unit, lock, bstr(name));
  1040.     if(!k) {
  1041.     packet->res1 = DOS_FALSE;
  1042.     packet->res2 = ERROR_NO_FREE_STORE;
  1043.     return;
  1044.     }
  1045.         
  1046.     if(-1 == stat(k->path, &statbuf)) {
  1047.     free_key(k);
  1048.     packet->res1 = DOS_FALSE;
  1049.     packet->res2 = ERROR_OBJECT_NOT_FOUND;
  1050.     return;
  1051.     }
  1052.  
  1053.     mode = statbuf.st_mode;
  1054.  
  1055.     if(mask & (1 << 3))
  1056.     mode &= ~S_IRUSR;
  1057.     else
  1058.     mode |= S_IRUSR;
  1059.     
  1060.     if(mask & (1 << 2) || mask & (1 << 0))
  1061.     mode &= ~S_IWUSR;
  1062.     else
  1063.     mode |= S_IWUSR;
  1064.  
  1065.     if(mask & (1 << 1))
  1066.     mode &= ~S_IXUSR;
  1067.     else
  1068.     mode |= S_IXUSR;
  1069.  
  1070.     if(-1 == chmod(k->path, mode)) {
  1071.     packet->res1 = DOS_FALSE;
  1072.     packet->res2 = dos_errno();
  1073.     } else {
  1074.     packet->res1 = DOS_TRUE;
  1075.     }
  1076.     free_key(k);
  1077. }
  1078.  
  1079. static void
  1080. action_same_lock(Unit* unit, DosPacket* packet)
  1081. {
  1082.     CPTR lock1 = packet->arg1 << 2;
  1083.     CPTR lock2 = packet->arg2 << 2;
  1084.  
  1085.     TRACE(("ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2));
  1086.     DUMPLOCK(lock1); DUMPLOCK(lock2);
  1087.  
  1088.     if(!lock1 || !lock2) {
  1089.     packet->res1 = (lock1 == lock2) ? DOS_TRUE : DOS_FALSE;
  1090.     } else {
  1091.     Key* key1 = (Key*) get_long(lock1 + 4);
  1092.     Key* key2 = (Key*) get_long(lock2 + 4);
  1093.     packet->res1 = (0 == strcmp(key1->path, key2->path)) ? DOS_TRUE : DOS_FALSE;
  1094.     }
  1095. }
  1096.  
  1097. static void
  1098. action_parent(Unit* unit, DosPacket* packet)
  1099. {
  1100.     CPTR lock = packet->arg1 << 2;
  1101.     Key*k;
  1102.  
  1103.     TRACE(("ACTION_PARENT(0x%lx)\n",lock));
  1104.     
  1105.     if(!lock) {
  1106.     packet->res1 = 0;
  1107.     packet->res2 = 0;
  1108.     return;
  1109.     }
  1110.  
  1111.     k = dup_key((Key*) get_long(lock + 4));
  1112.     if(0 == strcmp(k->path, unit->ui.rootdir)) {
  1113.     free_key(k);
  1114.     packet->res1 = 0;
  1115.     packet->res2 = 0;
  1116.     return;
  1117.     }
  1118.     {
  1119.     char *x = strrchr(k->path,'/');
  1120.     if(!x) {
  1121.         free_key(k);
  1122.         packet->res1 = 0;
  1123.         packet->res2 = 0;
  1124.         return;
  1125.     } else {
  1126.         *x = '\0';
  1127.     }
  1128.     }
  1129.     packet->res1 = make_lock(unit, k, -2) >> 2;
  1130. }
  1131.  
  1132. static void
  1133. action_create_dir(Unit* unit, DosPacket* packet)
  1134. {
  1135.     CPTR lock = packet->arg1 << 2;
  1136.     CPTR name = packet->arg2 << 2;
  1137.     Key* k;
  1138.  
  1139.     TRACE(("ACTION_CREATE_DIR(0x%lx,\"%s\")\n",lock,bstr(name)));
  1140.  
  1141.     if(unit->ui.readonly) {
  1142.     packet->res1 = DOS_FALSE;
  1143.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1144.     return;
  1145.     }
  1146.  
  1147.     k = make_key(unit, lock, bstr(name));
  1148.  
  1149.     if(!k) {
  1150.     packet->res1 = DOS_FALSE;
  1151.     packet->res2 = ERROR_NO_FREE_STORE;
  1152.     return;
  1153.     }
  1154.     if(-1 == mkdir(k->path, 0777)) {
  1155.     packet->res1 = DOS_FALSE;
  1156.     packet->res2 = dos_errno();
  1157.     free_key(k);
  1158.     return;
  1159.     }
  1160.     packet->res1 = make_lock(unit, k, -2) >> 2;
  1161. }
  1162.  
  1163. static void
  1164. action_delete_object(Unit* unit, DosPacket* packet)
  1165. {
  1166.     CPTR lock = packet->arg1 << 2;
  1167.     CPTR name = packet->arg2 << 2;
  1168.     Key* k;
  1169.     struct stat statbuf;
  1170.  
  1171.     TRACE(("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n",lock,bstr(name)));
  1172.  
  1173.     if(unit->ui.readonly) {
  1174.     packet->res1 = DOS_FALSE;
  1175.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1176.     return;
  1177.     }
  1178.  
  1179.     k = make_key(unit, lock, bstr(name));
  1180.  
  1181.     if(!k) {
  1182.     packet->res1 = DOS_FALSE;
  1183.     packet->res2 = ERROR_NO_FREE_STORE;
  1184.     return;
  1185.     }
  1186.     if(-1 == stat(k->path, &statbuf)) {
  1187.     packet->res1 = DOS_FALSE;
  1188.     packet->res2 = dos_errno();
  1189.     free_key(k);
  1190.     return;
  1191.     }
  1192.     if(S_ISDIR(statbuf.st_mode)) {
  1193.     if(-1 == rmdir(k->path)) {
  1194.         packet->res1 = DOS_FALSE;
  1195.         packet->res2 = dos_errno();
  1196.         free_key(k);
  1197.         return;
  1198.     }
  1199.     } else {
  1200.     if(-1 == unlink(k->path)) {
  1201.         packet->res1 = DOS_FALSE;
  1202.         packet->res2 = dos_errno();
  1203.         free_key(k);
  1204.         return;
  1205.     }
  1206.     }
  1207.     free_key(k);
  1208.     packet->res1 = DOS_TRUE;
  1209. }
  1210.  
  1211. static void
  1212. action_set_date(Unit* unit, DosPacket* packet)
  1213. {
  1214.     CPTR lock = packet->arg2 << 2;
  1215.     CPTR name = packet->arg3 << 2;
  1216.     CPTR date = packet->arg4;
  1217.     Key* k;
  1218.     struct utimbuf ut;
  1219.     
  1220.     TRACE(("ACTION_SET_DATE(0x%lx,\"%s\")\n",lock,bstr(name)));
  1221.  
  1222.     if(unit->ui.readonly) {
  1223.     packet->res1 = DOS_FALSE;
  1224.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1225.     return;
  1226.     }
  1227.  
  1228.     ut.actime = ut.modtime = put_time(get_long(date),get_long(date+4),get_long(date+8));
  1229.     k = make_key(unit, lock, bstr(name));
  1230.  
  1231.     if(!k) {
  1232.     packet->res1 = DOS_FALSE;
  1233.     packet->res2 = ERROR_NO_FREE_STORE;
  1234.     return;
  1235.     }
  1236.     if(-1 == utime(k->path, &ut)) {
  1237.     packet->res1 = DOS_FALSE;
  1238.     packet->res2 = dos_errno();
  1239.     free_key(k);
  1240.     return;
  1241.     }
  1242.     free_key(k);
  1243.     packet->res1 = DOS_TRUE;
  1244. }
  1245.  
  1246. static void
  1247. action_rename_object(Unit* unit, DosPacket* packet)
  1248. {
  1249.     CPTR lock1 = packet->arg1 << 2;
  1250.     CPTR name1 = packet->arg2 << 2;
  1251.     Key* k1;
  1252.     CPTR lock2 = packet->arg3 << 2;
  1253.     CPTR name2 = packet->arg4 << 2;
  1254.     Key* k2;
  1255.  
  1256.     TRACE(("ACTION_RENAME_OBJECT(0x%lx,\"%s\",",lock1,bstr(name1)));
  1257.     TRACE(("0x%lx,\"%s\")\n",lock2,bstr(name2)));
  1258.  
  1259.     if(unit->ui.readonly) {
  1260.     packet->res1 = DOS_FALSE;
  1261.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1262.     return;
  1263.     }
  1264.  
  1265.     k1 = make_key(unit, lock1, bstr(name1));
  1266.     if(!k1) {
  1267.     packet->res1 = DOS_FALSE;
  1268.     packet->res2 = ERROR_NO_FREE_STORE;
  1269.     return;
  1270.     }
  1271.     k2 = make_key(unit, lock2, bstr(name2));
  1272.     if(!k2) {
  1273.     free_key(k1);
  1274.     packet->res1 = DOS_FALSE;
  1275.     packet->res2 = ERROR_NO_FREE_STORE;
  1276.     return;
  1277.     }
  1278.     
  1279.     if(-1 == rename(k1->path, k2->path)) {
  1280.     packet->res1 = DOS_FALSE;
  1281.     packet->res2 = dos_errno();
  1282.     free_key(k1);
  1283.     free_key(k2);
  1284.     return;
  1285.     }
  1286.     free_key(k1);
  1287.     free_key(k2);
  1288.     packet->res1 = DOS_TRUE;
  1289. }
  1290.  
  1291. static void
  1292. action_current_volume(Unit* unit, DosPacket* packet)
  1293. {
  1294.     packet->res1 = unit->volume >> 2;
  1295. }
  1296.  
  1297. static void
  1298. action_rename_disk(Unit* unit, DosPacket* packet)
  1299. {
  1300.     CPTR name = packet->arg1 << 2;
  1301.     int i;
  1302.     int namelen;
  1303.  
  1304.     TRACE(("ACTION_RENAME_DISK(\"%s\")\n", bstr(name)));
  1305.  
  1306.     if(unit->ui.readonly) {
  1307.     packet->res1 = DOS_FALSE;
  1308.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1309.     return;
  1310.     }
  1311.  
  1312.     /* get volume name */
  1313.     namelen = get_byte(name++);
  1314.     free(unit->ui.volname);
  1315.     unit->ui.volname = (char *) malloc(namelen + 1);
  1316.     for(i = 0; i < namelen; i++)
  1317.     unit->ui.volname[i] = get_byte(name++);
  1318.     unit->ui.volname[i] = 0;
  1319.     
  1320.     put_byte(unit->volume + 44, namelen);
  1321.     for(i = 0; i < namelen; i++)
  1322.     put_byte(unit->volume + 45 + i, unit->ui.volname[i]);
  1323.     
  1324.     packet->res1 = DOS_TRUE;
  1325. }
  1326.  
  1327. static void
  1328. action_is_filesystem(Unit* unit, DosPacket* packet)
  1329. {
  1330.     packet->res1 = DOS_TRUE;
  1331. }
  1332.  
  1333. static void
  1334. action_flush(Unit* unit, DosPacket* packet)
  1335. {
  1336.     /* sync(); */ /* pretty drastic, eh */
  1337.     packet->res1 = DOS_TRUE;
  1338. }
  1339.  
  1340. static ULONG
  1341. filesys_handler(void)
  1342. {
  1343.     DosPacket packet;
  1344.     Unit *unit = find_unit(regs.a[5]);
  1345.     
  1346.     /* got DosPacket in A4 */
  1347.     packet.addr = regs.a[4];
  1348.     packet.type = get_long(packet.addr + dp_Type);
  1349.     packet.res1 = get_long(packet.addr + dp_Res1);
  1350.     packet.res2 = get_long(packet.addr + dp_Res2);
  1351.     packet.arg1 = get_long(packet.addr + dp_Arg1);
  1352.     packet.arg2 = get_long(packet.addr + dp_Arg2);
  1353.     packet.arg3 = get_long(packet.addr + dp_Arg3);
  1354.     packet.arg4 = get_long(packet.addr + dp_Arg4);
  1355.  
  1356.     if(!unit) {
  1357.     startup(&packet);
  1358.     put_long(packet.addr + dp_Res1, packet.res1);
  1359.     put_long(packet.addr + dp_Res2, packet.res2); 
  1360.     return 0;
  1361.     }
  1362.  
  1363.     if(!unit->volume) {
  1364.     printf("no volume\n");
  1365.     return 0;
  1366.     }
  1367.  
  1368.     switch(packet.type) {
  1369.      case ACTION_LOCATE_OBJECT:
  1370.     action_lock(unit, &packet);
  1371.     break;
  1372.  
  1373.      case ACTION_FREE_LOCK:
  1374.     action_free_lock(unit, &packet);
  1375.     break;
  1376.  
  1377.      case ACTION_COPY_DIR:
  1378.     action_dup_lock(unit, &packet);
  1379.     break;
  1380.  
  1381.      case ACTION_DISK_INFO:
  1382.     action_disk_info(unit, &packet);
  1383.     break;
  1384.  
  1385.      case ACTION_INFO:
  1386.     action_info(unit, &packet);
  1387.     break;
  1388.  
  1389.      case ACTION_EXAMINE_OBJECT:
  1390.     action_examine_object(unit, &packet);
  1391.     break;
  1392.  
  1393.      case ACTION_EXAMINE_NEXT:
  1394.     action_examine_next(unit, &packet);
  1395.     break;
  1396.  
  1397.      case ACTION_FIND_INPUT:
  1398.     action_find_input(unit, &packet);
  1399.     break;
  1400.  
  1401.      case ACTION_FIND_WRITE:
  1402.     action_find_write(unit, &packet);
  1403.     break;
  1404.  
  1405.      case ACTION_FIND_OUTPUT:
  1406.     action_find_output(unit, &packet);
  1407.     break;
  1408.  
  1409.      case ACTION_END:
  1410.     action_end(unit, &packet);
  1411.     break;
  1412.  
  1413.      case ACTION_READ:
  1414.     action_read(unit, &packet);
  1415.     break;
  1416.  
  1417.      case ACTION_WRITE:
  1418.     action_write(unit, &packet);
  1419.     break;
  1420.     
  1421.      case ACTION_SEEK:
  1422.     action_seek(unit, &packet);
  1423.     break;
  1424.     
  1425.      case ACTION_SET_PROTECT:
  1426.     action_set_protect(unit, &packet);
  1427.     break;
  1428.     
  1429.      case ACTION_SAME_LOCK:
  1430.     action_same_lock(unit, &packet);
  1431.     break;
  1432.     
  1433.      case ACTION_PARENT:
  1434.     action_parent(unit, &packet);
  1435.     break;
  1436.     
  1437.      case ACTION_CREATE_DIR:
  1438.     action_create_dir(unit, &packet);
  1439.     break;
  1440.     
  1441.      case ACTION_DELETE_OBJECT:
  1442.     action_delete_object(unit, &packet);
  1443.     break;
  1444.     
  1445.      case ACTION_RENAME_OBJECT:
  1446.     action_rename_object(unit, &packet);
  1447.     break;
  1448.     
  1449.      case ACTION_SET_DATE:
  1450.     action_set_date(unit, &packet);
  1451.     break;
  1452.     
  1453.      case ACTION_CURRENT_VOLUME:
  1454.     action_current_volume(unit, &packet);
  1455.     break;
  1456.     
  1457.      case ACTION_RENAME_DISK:
  1458.     action_rename_disk(unit, &packet);
  1459.     break;
  1460.     
  1461.      case ACTION_IS_FILESYSTEM:
  1462.     action_is_filesystem(unit, &packet);
  1463.     break;
  1464.     
  1465.      case ACTION_FLUSH:
  1466.     action_flush(unit, &packet);
  1467.     break;
  1468.     
  1469.      default:
  1470.     TRACE(("*** UNSUPPORTED PACKET %ld\n", packet.type));
  1471.     packet.res1 = DOS_FALSE;
  1472.     packet.res2 = ERROR_ACTION_NOT_KNOWN;
  1473.     break;
  1474.     }
  1475.  
  1476.     put_long(packet.addr + dp_Res1, packet.res1);
  1477.     put_long(packet.addr + dp_Res2, packet.res2); 
  1478.     TRACE(("reply: %8lx, %ld\n", packet.res1, packet.res2));
  1479.  
  1480.     return 0;
  1481. }
  1482.  
  1483. static ULONG
  1484. filesys_init(void)
  1485. {
  1486.     ULONG tmp1, tmp2;
  1487.     bool have36 = false;
  1488.     int i;
  1489.  
  1490.     regs.d[0] = 88; regs.d[1] = 1; /* MEMF_PUBLIC */
  1491.     tmp1 = CallLib (regs.a[6], -198); /* AllocMem() */
  1492.     if (tmp1 == 0) {
  1493.     fprintf(stderr, "Not enough memory for filesystem!\n");
  1494.     return 0;
  1495.     }
  1496.  
  1497.     /* Open expansion.lib */
  1498.     regs.d[0] = 36; /* Let's try this... */
  1499.     regs.a[1] = explibname;
  1500.     regs.a[4] = CallLib (regs.a[6], -552); /* OpenLibrary() */
  1501.     if (regs.a[4])
  1502.     have36 = true;
  1503.     else {
  1504.     regs.d[0] = 0;
  1505.     regs.a[1] = explibname;
  1506.     regs.a[4] = CallLib (regs.a[6], -552); /* OpenLibrary() */
  1507.     }
  1508.     put_long (tmp1+4, fsdevname);
  1509.     put_long (tmp1+12, 0); /* Device flags */
  1510.     put_long (tmp1+16, 16); /* Env. size */
  1511.     put_long (tmp1+20, 128); /* 512 bytes/block */
  1512.     put_long (tmp1+24, 0); /* unused */
  1513.     put_long (tmp1+28, 1); /* heads */
  1514.     put_long (tmp1+32, 1); /* unused */
  1515.     put_long (tmp1+36, 32); /* secs per track */
  1516.     put_long (tmp1+40, 1); /* reserved blocks */
  1517.     put_long (tmp1+44, 0); /* unused */
  1518.     put_long (tmp1+48, 0); /* interleave */
  1519.     put_long (tmp1+52, 0); /* lowCyl */
  1520.     put_long (tmp1+56, 511); /* upperCyl */
  1521.     put_long (tmp1+60, 0); /* Number of buffers */
  1522.     put_long (tmp1+64, 0); /* Buffer mem type */
  1523.     put_long (tmp1+68, 0x7FFFFFFF); /* largest transfer */
  1524.     put_long (tmp1+72, ~1); /* addMask (?) */
  1525.     put_long (tmp1+76, (ULONG)-1); /* bootPri */
  1526.     if (have36)
  1527.     put_long (tmp1+80, 0x444f5301); /* DOS\1 */
  1528.     else
  1529.     put_long (tmp1+80, 0x444f5300); /* DOS\0 */
  1530.     
  1531.     put_long (tmp1+84, 0); /* pad */
  1532.  
  1533.     /* re-use the same parameter packet to make each
  1534.      * dos node, which will then get tweaked
  1535.      */
  1536.     for(i = 0; i < num_units; i++) {
  1537.     put_long (tmp1, devnameaddr[i]);
  1538.     put_long (tmp1+8, i); /* Unit no. (not really necessary) */
  1539.     regs.a[0] = tmp1;
  1540.     tmp2 = CallLib (regs.a[4], -144); /* MakeDosNode() */
  1541.     put_long(tmp2+8, 0x0); /* dn_Task */
  1542.     put_long(tmp2+16, 0x0); /* dn_Handler */
  1543.     put_long(tmp2+20, 4000); /* dn_StackSize */
  1544.     put_long(tmp2+32, filesysseglist >> 2); /* dn_SegList */
  1545.     put_long(tmp2+36, (ULONG)-1); /* dn_GlobalVec */
  1546.     
  1547.     regs.a[0] = tmp2;
  1548.     regs.d[0] = (ULONG)-1;
  1549.     regs.a[1] = 0;
  1550.     regs.d[1] = 0;
  1551.     CallLib (regs.a[4], -150); /* AddDosNode() */
  1552.     }
  1553.  
  1554.     regs.a[1] = tmp1;
  1555.     regs.d[0] = 88;
  1556.     CallLib (regs.a[6], -210); /* FreeMem() */
  1557.  
  1558.     regs.a[1] = regs.a[4];
  1559.     CallLib (regs.a[6], -414); /* CloseLibrary() */
  1560.  
  1561.     return 0;
  1562. }
  1563.  
  1564. void
  1565. filesys_install(void)
  1566. {
  1567.     ULONG begin, end, resname, resid;
  1568.     int i;
  1569.  
  1570.     if(0 == num_units)
  1571.     return;
  1572.  
  1573.     resname = ds("UAEunixfs.resource");
  1574.     resid = ds("UAE unixfs 0.1");
  1575.  
  1576.     doslibname = ds("dos.library");
  1577.     fsdevname = ds("unixfs.device"); /* does not really exist */
  1578.  
  1579.     for(i = 0; i < num_units; i++) {
  1580.     devnameaddr[i] = ds(ui[i].devname);
  1581.     }
  1582.  
  1583.     begin = here();
  1584.     dw(0x4AFC); /* RTC_MATCHWORD */
  1585.     dl(begin); /* our start address */
  1586.     dl(0); /* Continue scan here */
  1587.     dw(0x0101); /* RTF_COLDSTART; Version 1 */
  1588.     dw(0x0805); /* NT_RESOURCE; pri 5 */
  1589.     dl(resname); /* name */
  1590.     dl(resid); /* ID */
  1591.     dl(here() + 4); /* Init area: directly after this */
  1592.  
  1593.     calltrap(deftrap(filesys_init)); dw(RTS);
  1594.  
  1595.     /* align */
  1596.     align(4);
  1597.     /* Fake seglist */
  1598.     dl(16);
  1599.     filesysseglist = here();
  1600.     dl(0); /* NextSeg */
  1601.  
  1602.     /* start of code */
  1603.  
  1604.     /* I don't trust calling functions that Wait() directly,
  1605.      * so here's a little bit of 68000 code to receive and send our
  1606.      * DosPackets
  1607.      */
  1608.     dw(0x2c79); dl(4);        /* move.l    $4,a6 */
  1609.     dw(0x2279); dl(0);        /* move.l    0,a1 */
  1610.     dw(0x4eae); dw(0xfeda);    /* jsr        FindTask(a6) */
  1611.     dw(0x2040);                /* move.l    d0,a0 */
  1612.     dw(0x4be8); dw(0x005c);    /* lea.l    pr_MsgPort(a0),a5 */
  1613.                     /* loop: */
  1614.     dw(0x204d);                /* move.l    a5,a0 */
  1615.     dw(0x4eae); dw(0xfe80);    /* jsr        WaitPort(a6) */
  1616.     dw(0x204d);                /* move.l    a5,a0 */
  1617.     dw(0x4eae); dw(0xfe8c);    /* jsr        GetMsg(a6) */
  1618.     dw(0x2840);                /* move.l    d0,a4 */
  1619.     dw(0x286c); dw(10);        /* move.l    LN_NAME(a4),a4 */
  1620.     calltrap(deftrap(filesys_handler));
  1621.     dw(0x226c);    dw(0);        /* move.l    dp_Link(a4),a1 */
  1622.     dw(0x206c); dw(4);        /* move.l    dp_Port(a4),a0 */
  1623.     dw(0x294d); dw(4);        /* move.l    a5,dp_Port(a4) */
  1624.     dw(0x4eae); dw(0xfe92);    /* jsr        PutMsg(a6) */
  1625.     dw(0x60d6);             /* bra.s    loop */
  1626.  
  1627.     end = here();
  1628.     org(begin + 6);
  1629.     dl(end);
  1630.  
  1631.     org(end);
  1632. }
  1633.  
  1634.